// Parser.java -- the implementation of class Parser
//
// Defines
//
//   class Parser;
//
// Parses the language
//
//   exp  ->  ( rest
//         |  #f
//         |  #t
//         |  ' exp
//         |  integer_constant
//         |  string_constant
//         |  identifier
//    rest -> )
//         |  exp+ [. exp] )
//
// and builds a parse tree.  Lists of the form (rest) are further
// `parsed' into regular lists and special forms in the constructor
// for the parse tree node class Cons.  See Cons.parseList() for
// more information.
//
// The parser is implemented as an LL(0) recursive descent parser.
// I.e., parseExp() expects that the first token of an exp has not
// been read yet.  If parseRest() reads the first token of an exp
// before calling parseExp(), that token must be put back so that
// it can be reread by parseExp() or an alternative version of
// parseExp() must be called.
//
// If EOF is reached (i.e., if the scanner returns a NULL) token,
// the parser returns a NULL tree.  In case of a parse error, the
// parser discards the offending token (which probably was a DOT
// or an RPAREN) and attempts to continue parsing with the next token.

class Parser {
  private Scanner scanner;
  private static boolean dotread = false;

  public Parser(Scanner s) { scanner = s; }
  
  public Node parseExp() {
  /* 
  Token tokentemp= scanner.getNextToken();    
   if (tokentemp.getType()!=Token.LPAREN) {
       System.err.print("Invalid Symbol"); 
       System.err.flush();
       scanner.getNextToken();
      }
  
   else
      
       
       
       
    return null;
   */
      
   return parseExp(scanner.getNextToken());   
      
      
  }
  
  
  
  protected Node parseExp(Token toktemp) {
     if (toktemp.getType() == Token.LPAREN)
         //return new Cons(parseRest(), new Nil());
         return parseRest();
     else if(toktemp.getType() == Token.TRUE )
         return new  BooleanLit(true);
     else if(toktemp.getType() == Token.FALSE )
         return new  BooleanLit(false);
     else if(toktemp.getType() == Token.INT ){
      IntToken  inttoktemp= (IntToken) toktemp;
         return new IntLit( inttoktemp.getIntVal());
     }
     else if(toktemp.getType() == Token.STRING ){
      StrToken  strtoktemp= (StrToken) toktemp;
         return new StrLit( strtoktemp.getStrVal());
     }
     else if(toktemp.getType() == Token.IDENT ){
      IdentToken  identoktemp= (IdentToken) toktemp;
         return new Ident( identoktemp.getName());
    
         
    
    
  }
  
  } 
  
  
  
  
 
  
  protected Node parseRest() {
    // TODO: write code for parsing rest
    return parseRest(scanner.getNextToken());
  }
 
  
  protected Node parseRest(Token tokentemp){
      
   if (tokentemp.getType() == Token.DOT)
        return parseDotexp();
      
   if (tokentemp.getType() == Token.RPAREN)
         //return new Cons(parseRest(), new Nil());
         return new Nil();
   else if ((tokentemp != null) && (dotread== false) )
    return new Cons(parseExp(tokentemp), parseRest());
   else  if (tokentemp == null)
    return new Nil(); // null
   else return
       parseRest();
      
  }
  
  
  
  
  
 protected Node parseDotexp(){
    return parseDotexp(scanner.getNextToken()); 
 }
  
 protected Node parseDotexp(Token tokentemp){
  dotread=true;
 //  if (tokentemp.getType()==Token.DOT)
   return   parseRest();
   
  
  //return parseExp(tokentemp);                                                                         
  
     
  }
  
  // TODO: Add any additional methods you might need.
 
  
 protected boolean isValid(Token tokentemp){
 if(tokentemp.getType()==Token.DOT)
     return true;
 else
 if(tokentemp.getType()==Token.FALSE)    
     return true;
 else
  if(tokentemp.getType()==Token.IDENT)    
     return true;
 else
  if(tokentemp.getType()==Token.INT)    
     return true;   
 else
  if(tokentemp.getType()==Token.LPAREN)    
     return true;   
 else
  if(tokentemp.getType()==Token.QUOTE)    
     return true;   
 else
  if(tokentemp.getType()==Token.RPAREN)    
     return true;   
 else
  if(tokentemp.getType()==Token.STRING)    
     return true;   
  else
  if(tokentemp.getType()==Token.TRUE)   
     return true;       
  else return false;
 }
};


